#pragma once
#include <string>
#include <vector>

enum simple_c_tokens{
	kUndefined,

	kComment,

	kDefine,
	kIf,
	kElse,
	kInclude,
	kIfdef,
	kIfndef,
	kEndif,
	kElif,
	kIncludeString,

	kNot,
	kLogicalAnd,
	kLogicalOr,
	kOpenParentheses,
	kCloseParentheses,
	kEndOfStatement,
	kOpenScope,
	kCloseScope,
	kStar,
	kComma,

	// comparison operators
	kEquals,
	kGreateEquals,
	kLowerEquals, 
	kNotEquals,
	kLower,
	kGreater,

	kTypedef,
	kIdentifier,

	kNumeralOct,
	kNumeralDec,
	kNumeralHex,

	kStringLiteral,
	kCharLiteral

	/*
	kUnsigned,
	kSigned,

	kChar,
	kShort,
	kInt,
	kLong,
	kFloat,
	kDouble,
	kVoid,
	*/
};


struct token{
	simple_c_tokens tag;
	std::string lexeme;
	size_t pos;

	token(simple_c_tokens t, const std::string &a_Lexeme, size_t p)
		: tag(t), lexeme(a_Lexeme), pos(p) {}
};

struct simple_c_lexer_undefined{
	simple_c_lexer_undefined(token t) : m_Token(t) {}
	token m_Token;
};

struct lexer_eof{};

class simple_c_lexer{
public:
	simple_c_lexer(const std::string &a_File);

	unsigned int line() const { return m_LineNumber; }
	token scan();
	std::string get_raw(size_t start, size_t end) { return std::string(m_Buffer.begin() + start, m_Buffer.begin() + end); }
private:
	std::string read_lexeme();
	token tokenize(const std::string &a_Lexeme);

	token preprocessor_token(token &t, const std::string &lexeme);
	token operator_token(token &t, const std::string &lexeme);
	token identifier_token(token &, const std::string &lexeme);
	token simple_c_lexer::numeral_token(token &t, const std::string &lexeme);
	token include_string_token(token &t, const std::string &lexeme);
	token broken_string_token(token &t, const std::string &lexeme);
	token comment_token(token &t, const std::string &lexeme);

	token make(simple_c_tokens t, const std::string &a_Lexeme);

	std::vector<char> m_Buffer;
	size_t m_BufferPos;
	size_t m_Begin;
	unsigned int m_LineNumber;
};